#include "Car.h"
#include "Matrix.h"
#include "main_box.h"
#include <iostream>
#include <windows.h>
#include <winuser.h>

#include "cv.h"
#include "highgui.h"
using namespace std;

//Image Projection http://mtlung.blogspot.jp/2008/10/blog-post.html 
Car *pCar (0);
const GLfloat X = 1690.0f;
const GLfloat Z = 1280.0f;
const GLfloat Y = -31.6f;
void Init()
{
	glShadeModel( GL_SMOOTH );
	glClearColor( 0.0, 0.0, 0.0, 0.0);
	glClearDepth( 1.0 );

	GLfloat Ambient[4] = { 1.0, 1.0, 1.0, 1.0 };
	GLfloat Diffuse[4] = { 0.7, 0.7, 0.7, 1.0 };
	GLfloat Position[4] = { 0.0, 0.0, -1.0, 0.0 };
	GLfloat GlobalLight[4] = { 0.1, 0.1, 0.1, 1.0 };
	GLfloat shininess[] = {100.0f};

	glLightfv( GL_LIGHT0, GL_AMBIENT, Ambient );
	glLightfv( GL_LIGHT0, GL_DIFFUSE, Diffuse );
	glLightfv( GL_LIGHT0, GL_POSITION, Position );
	glLightfv( GL_LIGHT0, GL_SHININESS, shininess );

	glLightModelfv( GL_LIGHT_MODEL_AMBIENT, GlobalLight );
	glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

	glEnable( GL_LIGHTING );
	glEnable( GL_LIGHT0 );
	glEnable( GL_COLOR_MATERIAL );
	glEnable( GL_DEPTH_TEST );
	glEnable( GL_CULL_FACE );
}
void redisplay()
{
	pCar->redisplay();
	glutPostRedisplay();
}
void Display()
{
	//Clear the buffers 
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	glPushMatrix();
	gluLookAt(pCar->getDisplacementX()+pCar->getCamera_x(), pCar->getCamera_y(), pCar->getDisplacementY()+pCar->getCamera_z(), 
		pCar->getDisplacementX(), 0, pCar->getDisplacementY(), 
		0, 1.0, 0);
	pCar->draw();
	glPopMatrix();
	glFlush();
	glutSwapBuffers();
}

IplImage* GetImage( int wndWidth, int wndHeight )
{
    GLubyte* frameData=(GLubyte*)malloc(wndWidth*wndHeight*3*sizeof(GLubyte));
    glReadPixels(0,0,wndWidth,wndHeight,GL_RGB,GL_UNSIGNED_BYTE,frameData);

    IplImage* SnapImage=cvCreateImageHeader(cvSize(wndWidth,wndHeight),IPL_DEPTH_8U,3);
    cvSetData( SnapImage, frameData,wndWidth*3); 
 
    cvFlip( SnapImage, SnapImage, 0 );
    cvCvtColor( SnapImage, SnapImage,CV_RGB2BGR);

    //free(frameData);

	return SnapImage;
}

void Reshape( int width, int high )
{
	if ( high == 0 )high = 1;
	glViewport( 0, 0, static_cast< GLsizei >( width ), static_cast< GLsizei >( high ) );
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	gluPerspective( 45.0, static_cast< GLdouble >( width ) / static_cast< GLdouble >( high ), 0.1, 10000.0 );
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
}

void keyboard(const unsigned char key, const int x, const int y)
{
	IplImage *img;
	switch(key)
	{
	case 'W':case 'w':
		//pCar->accelerate(0.1f);
		pCar->move(3.14/360, 0, 0);
		break;
	case 'S':case 's':
		//pCar->decelerate(0.1f);
		pCar->move(-3.14/360, 0, 0);
		break;
	case 'D':case 'd':
		//pCar->turnRight(30.0f);
		pCar->move(0, 3.14/360, 0);
		break;
	case 'A':case 'a':
		//pCar->turnLeft(30.0f);
		pCar->move(0, -3.14/360, 0);
		break;
	case 'j':case 'J':
		//pCar->accelerate(0.1f);
		pCar->move(0, 0, 1.0f);
		break;
	case 'k':case 'K':
		//pCar->decelerate(0.1f);
		pCar->move(0, 0, -1.0f);
		break;
	case 'p':case 'P':
		//pCar->decelerate(0.1f);
		img = GetImage(800, 600);
		cvNamedWindow( "Image", 1 );
		cvShowImage("Image", img);
		cvWaitKey();
		break;
	case ' ':
		pCar->brake();
		break;
	default:
		return;
	}
	glutPostRedisplay();
}
int main( int argc, char* argv[] )
try
{
	main_box(argc, argv);
	pCar = new Car("Car.3DS");
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
	glutInitWindowSize( 800, 600 );
	glutInitWindowPosition( 100, 100 );
	glutCreateWindow( "MySystem" );
	Init();
	glutDisplayFunc( Display );
	glutReshapeFunc( Reshape );
	glutIdleFunc( redisplay );
	glutKeyboardFunc(keyboard);
	glutMainLoop();
	delete pCar;
	return 0;
}
catch(const std::runtime_error e)
{
	std::cerr << e.what() << std::endl;
	return 0;
}
catch(...)
{
	std::cerr << "ERROR!" << std::endl;
	return 0;
}